package com.vmock.base.core.response;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.vmock.base.utils.ContextUtils;
import com.vmock.base.utils.OutMsgUtils;
import com.vmock.base.utils.SpringUtils;
import com.vmock.biz.entity.Response;
import com.vmock.biz.entity.Url;
import com.vmock.biz.service.IResponseService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

import static com.vmock.base.utils.BizUtils.doOutResponse;


/**
 * 手动模式的响应处理
 *
 * @author vt
 * @since 2020-5-14
 */
@Slf4j
public class ManualIResponseStrategy implements IResponseStrategy {

    /**
     * response service
     */
    private IResponseService responseService = SpringUtils.getBean(IResponseService.class);

    private static final String MOCK_FOLDER_NAME = "v-mock";



    @Override
    public IMockResponse doResponse(Url mockUrl) {
        // 查询对应的返回entity
        Response mockResponse = responseService.selectMainResponse(mockUrl.getUrlId());
        // get resp and req from context
        HttpServletResponse response = ContextUtils.getResponse();
        HttpServletRequest request = ContextUtils.getRequest();
        // null check
        if (mockResponse == null) {
            OutMsgUtils.notFondResponse(response);
            return null;
        }
        //method check
        if (!request.getMethod().equalsIgnoreCase(mockResponse.getMethod())) {
            OutMsgUtils.methodNotValid(response);
            return null;
        }
        // 判断是否执行自定义python脚本
        if (StringUtils.isNotBlank(mockResponse.getDescription()) && mockResponse.getDescription().contains("python")) {
            mockResponse.setContent(executeCommand("python", mockResponse.getContent(), mockUrl.getRequestContent(), ".py"));
        } else if (StringUtils.isNotBlank(mockResponse.getDescription()) && mockResponse.getDescription().contains("mock")) {
            String nodeJsTemplate = "const fs = require('fs');\n" +
                    "const path = require('path');\n" +
                    "const Mock = require('mockjs');\n" +
                    "\n" +
                    "// Check if the data.json file path is provided as a command-line argument\n" +
                    "if (process.argv.length < 3) {\n" +
                    "    console.error('Usage: node main.js <data_json_path>');\n" +
                    "    process.exit(1);\n" +
                    "}\n" +
                    "\n" +
                    "const dataJsonPath = process.argv[2];\n" +
                    "\n" +
                    "// Read the data from the provided file path\n" +
                    "fs.readFile(dataJsonPath, 'utf8', (err, jsonData) => {\n" +
                    "    if (err) {\n" +
                    "        console.error(`Error reading ${dataJsonPath}:`, err);\n" +
                    "        return;\n" +
                    "    }\n" +
                    "\n" +
                    "    try {\n" +
                    "        const data = JSON.parse(jsonData);\n" +
                    "        // Use Mock.mock with the data read from the file\n" +
                    "        const result = Mock.mock(data);\n" +
                    "\n" +
                    "        // Generate a random file name using the current timestamp and a random number\n" +
                    "        const randomFileName = `${Date.now()}-${Math.floor(Math.random() * 10000)}.json`;\n" +
                    "        const outputFilePath = path.join(__dirname, randomFileName);\n" +
                    "        \n" +
                    "        // Write the result to the output file\n" +
                    "        fs.writeFile(outputFilePath, JSON.stringify(result, null, 4), 'utf8', (err) => {\n" +
                    "            if (err) {\n" +
                    "                console.error(`Error writing to ${outputFilePath}:`, err);\n" +
                    "                return;\n" +
                    "            }\n" +
                    "\n" +
                    "            console.log(`${outputFilePath}`);\n" +
                    "        });\n" +
                    "    } catch (parseError) {\n" +
                    "        console.error(`Error parsing ${dataJsonPath}:`, parseError);\n" +
                    "    }\n" +
                    "});";
            mockResponse.setContent(executeCommand("node", nodeJsTemplate, mockResponse.getContent(), ".js"));
        }
        // 执行请求
        doOutResponse(mockResponse, response);
        return mockResponse;
    }

    private String executeCommand(String executeType, String pythonScript, String argsPath, String fileType) {
        // 创建并获取临时文件路径
        String tempFilePath = createTempFile(pythonScript, fileType);
        // 参数放入临时文件内
        String argsTempFilePath = createTempFile(argsPath, ".txt");
        // 执行脚本并获取结果文件
        String[] result = executeScript(executeType, tempFilePath, argsTempFilePath);

        // 删除临时文件
        deleteTempFile(tempFilePath);
        deleteTempFile(argsTempFilePath);

        if("1".equals(result[1])) {
            return result[0];
        }
        // 从文件读取
        try {
            String content = CollUtil.join(Files.readAllLines(Paths.get(result[0].trim())), "\n");
            deleteTempFile(result[0].trim());
            return content;
        } catch (IOException e) {
            log.error("read file error", e);
            return result[0];
        }
    }

    private String createTempFile(String pythonScript, String fileType) {
        try {
            // 获取当前用户的根目录
            String userHome = System.getProperty("user.home");

            // 构建v-mock文件夹的完整路径
            String mockFolderPath = userHome + File.separator + MOCK_FOLDER_NAME;

            // 创建v-mock文件夹（如果不存在）
            Files.createDirectories(Paths.get(mockFolderPath));

            // 生成随机的UUID作为临时文件名
            String tempFileName = UUID.randomUUID().toString() + fileType;

            // 构建临时文件的完整路径
            String tempFilePath = mockFolderPath + File.separator + tempFileName;

            // 将Python脚本写入临时文件
            try (PrintWriter writer = new PrintWriter(tempFilePath)) {
                writer.write(pythonScript);
            }

            return tempFilePath;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private String[] executeScript(String executeType, String filePath, String args) {
        String successResult = "";
        String errorResult = "";
        try {
            String[] cmdArray = {executeType, filePath, args};

            Process process = Runtime.getRuntime().exec(cmdArray);
            // 处理Python脚本的输出

            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    successResult += line + "\n";
                }
            }
            // 获取执行失败的错误信息
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    errorResult += line + "\n";
                }
            }
            process.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        return StringUtils.isNotBlank(successResult) ? new String[]{successResult, "0"} : new String[]{errorResult, "1"};
    }

    private void deleteTempFile(String filePath) {
        try {
            Files.deleteIfExists(Paths.get(filePath));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
